/************************************************************************

								Heroes IV
					  Copyright 2000, The 3DO Company

	------------------------------------------------------------------
  						       abstract_town.cpp

	$Header: /game/abstract_town.cpp $

	$NoKeywords: $

 ************************************************************************/

// kill the 255+ character identifier warning.  Templates tend to exceed that easily.
#include "precompiled.h"
#pragma warning( disable: 4786 )

#include "abstract_town.h"

#include <algorithm>

#include "abstract_script_action.h"
#include "adventure_map.h"
#include "ai_importance.h"
#include "bitset_io.h"
#include "building_traits.h"
#include "enum_operations.h"
#include "external_string.h"
#include "hero.h"
#include "ownable_event.h"
#include "player.h"
#include "player_color.h"
#include "replace_keywords.h"
#include "scriptable_event.h"
#include "skill_set.h"
#include "timed_event.h"
#include "triggerable_event.h"
#include "town_image_level.h"
#include "town_properties.h"
#include "town_type.h"
#include "town_window.h"

extern t_external_string const k_named_object_balloon_help( "named_object_balloon_help" );

// -----------------------------------------------------------
// unnamed namespace
// -----------------------------------------------------------

namespace
{

	int const k_current_map_format_version = 8;

	// --------------------------------------------------------
	// --------------------------------------------------------
	bool read_old_built_in_event(
		std::streambuf &			stream,
		int							version,
		t_ownable_built_in_event &	event )
	{
		if ( get< t_uint8 >( stream ) == 0 )
			return true;

		t_ownable_built_in_event::t_script_ptr new_script_ptr =
			t_ownable_built_in_event::t_script::reconstruct( stream, version );

		if ( new_script_ptr.get() == 0 )
			return false;

		event.set_script( new_script_ptr );

		return true;
	}

	// -------------------------------------------------------------------
	// -------------------------------------------------------------------
	bool read_old_timed_event(
		std::streambuf &		stream,
		int						version,
		t_ownable_timed_event &	event )
	{
		int first_occurrence = get< t_uint16 >( stream );
		int recurrence_interval = get< t_uint16 >( stream );

		bool execution_flag = false;
		if ( version >= 1 )
		{
			get< bool >( stream ); // Discard "current player only" flag
			execution_flag = get< bool >( stream );
		}

		t_ownable_timed_event::t_script_ptr script_ptr =
			t_ownable_timed_event::t_script::reconstruct( stream, version );
		if ( script_ptr.get() == 0 )
			return false;

		event.set_first_occurrence( first_occurrence );
		event.set_recurrence_interval( recurrence_interval );
		if ( execution_flag )
			event.set_execution_flag();
		else
			event.clear_execution_flag();
		event.set_script( script_ptr );

		return true;
	}
} // unnamed namespace



// -----------------------------------------------------------
// town data
// -----------------------------------------------------------
t_abstract_town::t_abstract_town( std::string const& model_name )
               : t_owned_adv_object( model_name )
{
	visit_town(this);

	m_type = k_town_type_count; // unknown

	m_ai_importance = k_ai_importance_normal;

	m_named_by_map = false;
	m_buildings.set( k_town_village_hall );
	m_buildings.set( k_town_prison );
	m_enabled_buildings.set();
	
	std::fill(
		&m_built_in_events[ 0 ],
		&m_built_in_events[ k_built_in_event_count ],
		t_built_in_event_ptr( new t_built_in_event ) );
}

// -----------------------------------------------------------
// town data
// transfer data from source
// -----------------------------------------------------------
t_abstract_town::t_abstract_town( t_abstract_town* source )
               : t_owned_adv_object( *source ), t_creature_array( source )
{
	visit_town(this);
	
	m_buildings = source->m_buildings;
	m_buildings.set( k_town_village_hall );
	m_buildings.set( k_town_prison );
	std::copy(
		&source->m_built_in_events[ 0 ],
		&source->m_built_in_events[ k_built_in_event_count ],
		&m_built_in_events[ 0 ] );
	m_continuous_events = source->m_continuous_events;
	m_enabled_buildings = source->m_enabled_buildings;
	m_name = source->m_name;
	m_named_by_map = source->m_named_by_map;
	m_timed_events = source->m_timed_events;
	m_triggerable_events = source->m_triggerable_events;
	m_type = source->m_type;
	m_ai_importance = source->m_ai_importance;
}

// -----------------------------------------------------------
// town data
// abstract town destruction
// -----------------------------------------------------------
t_abstract_town::~t_abstract_town()
{
	// Make sure no pointers are left to this town
	clear_nobility_heroes();
}

// -------------------------------------------------------------------
// Called from ~t_adventure_map; last chance to clean up
// -------------------------------------------------------------------
void t_abstract_town::on_adventure_map_destruction()
{
	// Break circular references
	clear_nobility_heroes();
}

// -----------------------------------------------------------
// Clear the m_nobility_heroes set
// -----------------------------------------------------------
void t_abstract_town::clear_nobility_heroes(void)
{
	while (!m_nobility_heroes.empty())
	{
		(*m_nobility_heroes.begin())->clear_nobility_town(); // Erases from m_nobility_heroes 
	}
}

int t_abstract_town::get_towndwelling_count( ) const
{
	t_town_building dwelling;
	int count = 0;
	for (dwelling = k_town_dwelling_1; dwelling <= k_town_dwelling_8; enum_incr(dwelling))
	{
		if (has(dwelling)) ++count;
	}
	assert(count <= t_town_window::k_dwelling_icon_count);
	return count;
}


// -----------------------------------------------------------
// town data
// -----------------------------------------------------------
t_town_image_level t_abstract_town::get_castle_level() const
{
	if (m_buildings[k_town_castle])
		return k_town_image_castle;
	if (m_buildings[k_town_citadel] )
		return k_town_image_citadel;
	if (m_buildings[k_town_fort] )
		return k_town_image_fort;
	return k_town_image_village;
}

// -----------------------------------------------------------
// town data
// Return info about the town or garrison's grail status. Note
// that we return a special grail source (actually, this object)
// which will return true if the town has a grail building even
// if the town is unowned.
// -----------------------------------------------------------
t_abstract_grail_data_source const & t_abstract_town::get_grail_data() const
{
	return *this;
}


// -----------------------------------------------------------
// town data
// -----------------------------------------------------------
std::string t_abstract_town::get_name() const
{
	return m_name;
}

// -----------------------------------------------------------
// town data
// -----------------------------------------------------------
std::string t_abstract_town::get_balloon_help() const
{
	return replace_keywords( k_named_object_balloon_help, 
							 "%name", m_name,
							 "%type", get_text( "name" ) );
}

// -----------------------------------------------------------
// get highest nobility bonus
// -----------------------------------------------------------
int t_abstract_town::get_nobility_bonus( void ) const
{
	t_hero *hero = get_best_nobility_hero();

	if (hero)
		return hero->get_skill_power(k_skill_nobility);
	else
		return 0;
}

// -----------------------------------------------------------
// get hero with highest nobility bonus
// -----------------------------------------------------------
t_hero * t_abstract_town::get_best_nobility_hero( void ) const
{
	int best_bonus = 0;
	int best_priority = std::numeric_limits<int>::min();
	t_hero * best_hero = NULL;
	t_hero_set_uncounted::const_iterator hero_iterator;

	for (hero_iterator = m_nobility_heroes.begin(); hero_iterator != m_nobility_heroes.end(); hero_iterator++)
	{
		t_hero * hero = *hero_iterator;

		assert(hero->get_nobility_town().get() == this);

		if (hero->is_dead() || hero->is_imprisoned())
			continue;

		int bonus = hero->get_skill_power(k_skill_nobility);
		int priority = hero->get_nobility_priority();

		if (bonus > best_bonus || ( bonus == best_bonus && priority > best_priority ) )
		{
			best_bonus = bonus;
			best_hero = hero;
			best_priority = priority;
		}
	}

	return best_hero;
}

// -----------------------------------------------------------
// Note that the hero is now adding his/her nobility bonus
// to this town
// -----------------------------------------------------------
void t_abstract_town::add_hero_to_nobility_list(t_hero *hero)
{
	assert(m_nobility_heroes.find(hero) == m_nobility_heroes.end());

	m_nobility_heroes.insert(hero);
}

// -----------------------------------------------------------
// Note that the hero is no longer adding his/her nobility bonus
// to this town
// -----------------------------------------------------------
void t_abstract_town::remove_hero_from_nobility_list(t_hero *hero)
{
	// Heroes can now be cloned and used as temporary structures by
	// the AI.  The following assert will fire off when a cloned 
	// hero is destroyed.  As such, it's been removed.

//	assert(m_nobility_heroes.find(hero) != m_nobility_heroes.end());

	m_nobility_heroes.erase(hero);
}

// -----------------------------------------------------------
// Get the highest nobility priority of any hero in the
// nobility list. Returns at least zero.
// -----------------------------------------------------------
int t_abstract_town::get_highest_nobility_priority() const
{
	int priority = 0;

	t_hero_set_uncounted::const_iterator hero_iterator;

	for (hero_iterator = m_nobility_heroes.begin(); hero_iterator != m_nobility_heroes.end(); hero_iterator++)
	{
		if ( (*hero_iterator)->get_nobility_priority() > priority )
			priority = (*hero_iterator)->get_nobility_priority();
	}

	return priority;
}

// -----------------------------------------------------------
// Get the lowest nobility priority of any hero in the
// nobility list. Returns at most zero.
// -----------------------------------------------------------
int t_abstract_town::get_lowest_nobility_priority() const
{
	int priority = 0;

	t_hero_set_uncounted::const_iterator hero_iterator;

	for (hero_iterator = m_nobility_heroes.begin(); hero_iterator != m_nobility_heroes.end(); hero_iterator++)
	{
		if ( (*hero_iterator)->get_nobility_priority() < priority )
			priority = (*hero_iterator)->get_nobility_priority();
	}

	return priority;
}


// -----------------------------------------------------------
// Override of t_abstract_grail_data_source function
// -----------------------------------------------------------
bool t_abstract_town::gets_global_grail_effects( t_town_type alignment ) const
{
	// Note: make sure unowned towns still give grail effects to their garrison
	if ( m_type == alignment && has( k_town_grail ) )
		return true;

	t_player * owner = get_owner();

	if ( owner && owner->gets_global_grail_effects( alignment ) )
		return true;

	return false;
}

// -----------------------------------------------------------
// town data
// -----------------------------------------------------------
bool t_abstract_town::write( std::streambuf& stream ) const
{
	get_towndwelling_count();	// trigger assert if too many

	t_owned_adv_object::write( stream );
	put_bitset( stream, m_buildings );
	put_bitset( stream, m_enabled_buildings );
	t_creature_array::write( stream );
	write_string16( stream, m_name );
	put<bool>( stream, m_named_by_map );
	put<t_town_type>( stream, m_type );
	write_events( stream );
	put< t_uint8 >( stream, m_ai_importance );
	return true;
}

// -----------------------------------------------------------
// town data
// -----------------------------------------------------------
bool t_abstract_town::read( std::streambuf&					 stream, 
							t_qualified_adv_object_type const& type,
							int								 version )
{
	t_owned_adv_object::read( stream, type, version );
	m_buildings = get_bitset<k_town_building_count>( stream );
	m_enabled_buildings = get_bitset<k_town_building_count>( stream );
	if (version < 14)
		t_creature_array::read_version( stream, 0 );
	else if (version < 19)
		t_creature_array::read_version( stream, 1 );
	else
		t_creature_array::read( stream ); // 19 and later allow creature array it's own version
	read_string16( stream, m_name );

	get_towndwelling_count();	// trigger assert if too many

	if (version < 10)
		m_named_by_map = !m_name.empty();
	else
		m_named_by_map = get< bool >( stream );

	m_type = get<t_town_type>( stream );
	read_events( stream, version );

	if ( version < 16 )
		m_ai_importance = k_ai_importance_normal;
	else
		m_ai_importance = t_ai_importance( get< t_uint8 >( stream ) );

	return true;
}


// -----------------------------------------------------------
// town data
// -----------------------------------------------------------
bool t_abstract_town::read_events( std::streambuf& stream, int version )
{
	int scripting_version = 0;

	if ( version < 5 )
		return true;

	if ( version > 5 )
		scripting_version = get< t_uint16 > (stream);

	t_built_in_event_id event_id;
	for (	event_id = t_built_in_event_id( 0 );
			event_id < k_built_in_event_count;
			enum_incr( event_id ) )
	{
		t_built_in_event_ptr new_event_ptr( new t_built_in_event );
		bool read_result;
		if ( version < 9 )
			read_result = read_old_built_in_event( stream, scripting_version, *new_event_ptr );
		else
			read_result = new_event_ptr->read( stream, scripting_version );
		if ( !read_result )
			return false;

		m_built_in_events[ event_id ] = new_event_ptr;
	}

	t_timed_event_list new_timed_events;
	t_triggerable_event_list new_triggerable_events;
	t_continuous_event_list new_continuous_events;
			
	// Read the timed events
	int count = get< t_uint16 >( stream );
	new_timed_events.reserve( count );

	while ( count > 0 )
	{
		t_timed_event_ptr new_event_ptr( new t_timed_event );
		bool read_result;
		if ( version < 9 )
			read_result = read_old_timed_event( stream, scripting_version, *new_event_ptr );
		else
			read_result = new_event_ptr->read( stream, scripting_version );

		new_timed_events.push_back( new_event_ptr );

		--count;
	}

	// Read the triggerable and continuous events
	count = get< t_uint16 >( stream );
	if ( version < 9 )
	{
		// Read and convert from the old format
		while ( count > 0 )
		{
			std::string name;
			if ( !read_string16( stream, name ) )
				return false;

			bool continuous = get< bool >( stream );

			bool current_player_only = true;
			if ( version >= 1 )
			{
				current_player_only = get< bool >( stream );
				get< bool >( stream ); // discard "execution" flag
			}

			t_script_event::t_script_ptr new_script_ptr =
				t_script_event::t_script::reconstruct( stream, scripting_version );
			if ( new_script_ptr.get() == 0 )
				return false;

			if ( continuous )
			{
				t_continuous_event_ptr new_event_ptr( new t_continuous_event );
				new_event_ptr->set_run_only_during_owners_turn( current_player_only );
				new_event_ptr->set_script( new_script_ptr );
				new_continuous_events.push_back( new_event_ptr );
			}
			else
			{
				t_triggerable_event_ptr new_event_ptr( new t_triggerable_event );
				new_event_ptr->set_name( name );
				new_event_ptr->set_script( new_script_ptr );
				new_triggerable_events.push_back( new_event_ptr );
			}

			--count;
		}
	}
	else
	{
		// Read triggerable events
		new_triggerable_events.reserve( count );

		while ( count > 0 )
		{
			t_triggerable_event_ptr new_event_ptr( new t_triggerable_event );
			if ( !new_event_ptr->read( stream, scripting_version ) )
				return false;

			new_triggerable_events.push_back( new_event_ptr );

			--count;
		}

		// Read continuous events
		count = get< t_uint16 >( stream );
		new_continuous_events.reserve( count );

		while ( count > 0 )
		{
			t_continuous_event_ptr new_event_ptr( new t_continuous_event );
			if ( !new_event_ptr->read( stream, scripting_version ) )
				return false;

			new_continuous_events.push_back( new_event_ptr );

			--count;
		}
	}

	m_timed_events.swap( new_timed_events );
	m_triggerable_events.swap( new_triggerable_events );
	m_continuous_events.swap( new_continuous_events );

	return true;
}

// -----------------------------------------------------------
// town data
// -----------------------------------------------------------
bool t_abstract_town::write_events( std::streambuf& stream ) const
{
	put < t_uint16 >( stream, t_abstract_script_action::get_version() );

	t_built_in_event_id event_id;
	for (	event_id = t_built_in_event_id( 0 );
			event_id < k_built_in_event_count;
			enum_incr( event_id ) )
	{
		if ( !m_built_in_events[ event_id ]->write( stream ) )
			return false;
	}
	
	int count = m_timed_events.size();
	put< t_uint16 >( stream, count );
	int i;
	for (i = 0; i < count; i++) {
		if (m_timed_events[i]->write( stream ) == false) 
			return false;
	}

	count = m_triggerable_events.size();
	put< t_uint16 >( stream, count );
	for (i = 0; i < count; i++) {
		if (m_triggerable_events[i]->write( stream ) == false) 
			return false;
	}

	count = m_continuous_events.size();
	put< t_uint16 >( stream, count );
	for (i = 0; i < count; i++) {
		if (m_continuous_events[i]->write( stream ) == false) 
			return false;
	}

	return true;

}

// -----------------------------------------------------------
// town data
// -----------------------------------------------------------
bool t_abstract_town::read_map_data( std::streambuf& stream, t_progress_handler* handler,
									 bool& custom_garrison, bool& custom_buildings,
									 bool & customized_school_skills, t_skill_set & available_school_skills, t_skill_set & required_school_skills )
{
	int version = get< t_uint16 >( stream );
	if ( version < 6 || version > k_current_map_format_version )
		return false;

	return read_map_data( stream, handler, custom_garrison, custom_buildings, customized_school_skills, available_school_skills, required_school_skills, version );
}

// -----------------------------------------------------------
// town data
// -----------------------------------------------------------
bool t_abstract_town::read_map_data( std::streambuf& stream, t_progress_handler*,
									 bool& custom_garrison, bool& custom_buildings,
									 bool & customized_school_skills, t_skill_set & available_school_skills, t_skill_set & required_school_skills,
									 int version )
{
	if ( version < 6 || version > k_current_map_format_version )
		return false;

	return		read_player_color_from_map( stream, version )
			&&	read_name_from_map( stream, version )
			&&	read_garrison_from_map( stream, version, custom_garrison )
			&&	read_buildings_from_map( stream, version, custom_buildings )
			&&	read_built_in_events_from_map( stream, version )
			&&	read_timed_events_from_map( stream, version )
			&&	read_triggerable_events_from_map( stream, version )
			&&	read_continuous_events_from_map( stream, version )
			&&  read_school_skills_from_map( stream, version, customized_school_skills, available_school_skills, required_school_skills )
			&&  read_ai_importance_from_map( stream, version );
}

// -----------------------------------------------------------
// town data
// -----------------------------------------------------------
bool t_abstract_town::preplacement( t_adventure_map& map, int pass )
{
	// At this point the owner number has not been set, so used the
	// player color
	return t_creature_array::preplacement( map, pass, map.get_player( get_player_color() ) );
}

// -----------------------------------------------------------
// Read AI importance
// -----------------------------------------------------------
bool t_abstract_town::read_ai_importance_from_map( std::streambuf &	stream, int version )
{
	if ( version < 8 )
	{
		m_ai_importance = k_ai_importance_normal;
	}
	else
	{
		m_ai_importance = t_ai_importance( get< t_uint8 >( stream ) );
	}

	return true;
}

// -----------------------------------------------------------
// town data
// -----------------------------------------------------------
bool t_abstract_town::read_buildings_from_map(
	std::streambuf &	stream,
	int					version,
	bool &				custom_buildings )
{
	if ( version < 3 )
	{
		custom_buildings = false;
		m_buildings.reset();
		m_buildings.set( k_town_fort );
		m_enabled_buildings.set();
		return true;
	}

	custom_buildings = get< t_uint8 >( stream ) != 0;
	if ( custom_buildings )
	{
		m_buildings = get_bitset< k_town_building_count >( stream );
		m_enabled_buildings = get_bitset< k_town_building_count >( stream );
	}
	else
	{
		m_buildings.reset();
		m_buildings.set( k_town_fort, get< t_uint8 >( stream ) != 0 );
		m_enabled_buildings.set();
	}

	get_towndwelling_count();	// trigger assert if too many

	return true;
}

// -----------------------------------------------------------
// town data
// -----------------------------------------------------------
bool t_abstract_town::read_built_in_events_from_map(
	std::streambuf &	stream,
	int					version )
{
	assert( version >= 6 );

	t_built_in_event_id event_id;
	for (	event_id = t_built_in_event_id( 0 );
			event_id < k_built_in_event_count;
			enum_incr( event_id ) )
	{
		t_built_in_event_ptr new_event_ptr( new t_built_in_event );
		if ( !new_event_ptr->read_from_map( stream ) )
			return false;

		m_built_in_events[ event_id ] = new_event_ptr;
	}

	return true;
}

// -----------------------------------------------------------
// town data
// -----------------------------------------------------------
bool t_abstract_town::read_garrison_from_map(
	std::streambuf &	stream,
	int					version,
	bool &				custom_garrison )
{
	if ( version < 2 )
	{
		custom_garrison = false;
		return true;
	}

	custom_garrison = get< t_uint8 >( stream ) != 0;
	return !custom_garrison || t_creature_array::read_from_map( stream );
}

// -----------------------------------------------------------
// town data
// -----------------------------------------------------------
bool t_abstract_town::read_name_from_map(
	std::streambuf &	stream,
	int					version )
{
	if ( version < 2 )
	{
		m_name = std::string();
		m_named_by_map = false;
		return true;
	}

	if (!::read_string16( stream, m_name ) )
		return false;

	m_named_by_map = !m_name.empty();

	return true;
}

// -----------------------------------------------------------
// town data
// -----------------------------------------------------------
bool t_abstract_town::read_player_color_from_map(
	std::streambuf &	stream,
	int					version )
{
	t_player_color new_player_color;
	if ( version >= 1 )
	{
		new_player_color = t_player_color( get< t_uint8 >( stream ) );
		if ( new_player_color < 0 || new_player_color >= k_player_color_count )
			return false;
	}
	else
		new_player_color = k_player_gray;
	set_player_color( new_player_color );

	return true;
}

// -----------------------------------------------------------
// town data
// -----------------------------------------------------------
bool t_abstract_town::read_timed_events_from_map(
	std::streambuf &	stream,
	int					version )
{
	assert( version >= 6 );

	int count = get< t_uint16 >( stream );
	t_timed_event_list new_timed_events;
	new_timed_events.reserve( count );

	while ( count > 0 )
	{
		t_timed_event_ptr new_event_ptr( new t_timed_event );
		if ( !new_event_ptr->read_from_map( stream ) )
			return false;

		new_timed_events.push_back( new_event_ptr );

		--count;
	}

	m_timed_events.swap( new_timed_events );
	return true;
}

// -----------------------------------------------------------
// town data
// -----------------------------------------------------------
bool t_abstract_town::read_triggerable_events_from_map(
	std::streambuf &	stream,
	int					version )
{
	assert( version >= 6 );

	int count = get< t_uint16 >( stream );
	t_triggerable_event_list new_triggerable_events;
	new_triggerable_events.reserve( count );

	while ( count > 0 )
	{
		t_triggerable_event_ptr new_event_ptr( new t_triggerable_event );
		if ( !new_event_ptr->read_from_map( stream ) )
			return false;

		new_triggerable_events.push_back( new_event_ptr );

		--count;
	}

	m_triggerable_events.swap( new_triggerable_events );
	return true;
}

// -----------------------------------------------------------
// town data
// -----------------------------------------------------------
bool t_abstract_town::read_continuous_events_from_map(
	std::streambuf &	stream,
	int					version )
{
	assert( version >= 6 );

	int count = get< t_uint16 >( stream );
	t_continuous_event_list new_continuous_events;
	new_continuous_events.reserve( count );

	while ( count > 0 )
	{
		t_continuous_event_ptr new_event_ptr( new t_continuous_event );
		if ( !new_event_ptr->read_from_map( stream ) )
			return false;

		new_continuous_events.push_back( new_event_ptr );

		--count;
	}

	m_continuous_events.swap( new_continuous_events );
	return true;
}

// -----------------------------------------------------------
// Read school skills from map. Return data in the reference
// parameters; the object is not actually changed
// -----------------------------------------------------------
bool t_abstract_town::read_school_skills_from_map( std::streambuf & stream, 
												   int version, 
												   bool & customized_school_skills, 
												   t_skill_set & available_school_skills, 
												   t_skill_set & required_school_skills )
{
	if ( version < 7 )
	{
		customized_school_skills = false;
		return true;
	}

	customized_school_skills = get< bool >( stream );

	if ( customized_school_skills )
	{
		if (    !available_school_skills.read( stream )
			 || !required_school_skills.read( stream ) )
		{
			return false;
		}
	}

	return true;
}

// --------------------------------------------------------------
// Cannot delete towns
// --------------------------------------------------------------
bool t_abstract_town::is_deleted_by_deletion_marker() const
{
	return false;
}

// -----------------------------------------------------------
// Additional handling for the destruction of an abstract town
// -----------------------------------------------------------
void t_abstract_town::destroy()
{
	clear_nobility_heroes();

	t_owned_adv_object::destroy();
}


// -----------------------------------------------------------------
// Additional handling for the ownership change of an abstract town
// -----------------------------------------------------------------
void t_abstract_town::set_owner( int player_number )
{
	if (player_number != get_owner_number())
	{
		if ( !m_nobility_heroes.empty() )
		{
			clear_nobility_heroes();

			// Any heroes which are in another town's garrison & which 
			// were linked to this town should go ahead & link to their
			// current town
			t_player * owner = get_owner();

			if ( owner )
			{
				owner->force_garrison_visits();
			}
		}
	}

	t_owned_adv_object::set_owner(player_number);

	// Just in case...
	visit_town(this);
}

// -----------------------------------------------------------------
// -----------------------------------------------------------------
void t_abstract_town::post_change()
{
	t_creature_array::post_change();

	visit_town( this );
}

// -----------------------------------------------------------------
// -----------------------------------------------------------------
int t_abstract_town::compute_scouting_range() const
{
	int const k_default_range = 15;

	int garrison_range = t_creature_array::compute_scouting_range();
	if ( garrison_range > k_default_range )
		return garrison_range;

	return k_default_range;
}

// -----------------------------------------------------------
// town data
// Call after read_from_map to initialize
// -----------------------------------------------------------
void t_abstract_town::initialize( t_adventure_map& map )
{
	t_owned_adv_object::initialize( map );

	t_creature_array::initialize();

	if ( m_name.empty() )
	{
		m_name = map.get_random_name( get_model_type() );
	}
}


// -----------------------------------------------------------
// town data
// Call after read to initialize
// -----------------------------------------------------------
void t_abstract_town::read_postplacement( t_adventure_map& map )
{
	t_owned_adv_object::read_postplacement( map );

	t_creature_array::read_postplacement( map );
}

